﻿using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace SwaggerExtensions
{
    public class DefaultValueSchemaFilter : ISchemaFilter
    {
        bool IsNullableType(Type that)
        {
            return !(that == null) && !that.IsArray && that.FullName.StartsWith("System.Nullable`1[");
        }
        bool IsBasicTypeExtended(Type type)
        {
            // 检查是否为原始类型
            if (type.IsPrimitive)
            {
                return true;
            }

            // 检查是否为其他我们认为是“基本”的类型
            if (type == typeof(string) ||
                  type == typeof(Nullable<int>) ||
                  type == typeof(Nullable<float>) ||
                  type == typeof(Nullable<long>) ||
                  type == typeof(Nullable<Int64>) ||
                type == typeof(decimal) ||
                  type == typeof(Nullable<decimal>) ||
                type == typeof(DateTime) ||
                 type == typeof(Nullable<DateTime>) ||
                type == typeof(TimeSpan) ||
                 type == typeof(Nullable<TimeSpan>) ||
                type == typeof(Guid))
            {
                return true;
            }

            // 默认情况下返回 false
            return false;
        }

        public void Apply(OpenApiSchema schema, SchemaFilterContext context)
        {
            if (schema.Properties == null)
            {
                return;
            }
            foreach (var propertyInfo in context.Type.GetProperties())
            {
                var defaultValue = (propertyInfo.GetCustomAttribute<DefaultValueAttribute>())?.Value;
                object? objvalue = null;
                if (context.Type.IsClass && !context.Type.IsAbstract
                    && !context.Type.IsGenericType && !context.Type.IsArray
                    && context.Type != typeof(string) && context.Type.IsPublic)
                {
                    try
                    {
                        var obj = Activator.CreateInstance(context.Type);

                        if (!IsNullableType(propertyInfo.PropertyType))
                        {
                            objvalue = propertyInfo.GetValue(obj);
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.ToString());
                    }
                }


                var val = defaultValue ?? objvalue;
                if (val == null && !IsBasicTypeExtended(propertyInfo.PropertyType))
                {
                    continue;
                }

                //var val = defaultValue;
                foreach (var (key, value) in schema.Properties)
                {
                    if (propertyInfo.Name.ToLower().Equals(key.ToLower()))
                    {
                        try
                        {
                            if (val is int intValue)
                            {
                                value.Example = new OpenApiInteger(intValue);
                                break;
                            }
                            else if (val is string stringValue)
                            {
                                value.Example = new OpenApiString(stringValue);
                                break;
                            }

                            else if (val is DateTime dateTimeValue)
                            {
                                if (dateTimeValue == default(DateTime))
                                {
                                    dateTimeValue = DateTime.Now;
                                }
                                var v = JSON.Serialize(dateTimeValue);
                                value.Example = new OpenApiString(v.Substring(1, v.Length - 2).Replace("\\", ""));
                                break;
                            }
                            else if (val is Boolean boolValue)
                            {
                                value.Example = new OpenApiBoolean(boolValue);
                                break;
                            }
                            else
                            {
                                value.Example = OpenApiAnyFactory.CreateFromJson(JSON.Serialize(val));
                                break;
                            }
                        }
                        catch (Exception ex)
                        {

                            Console.WriteLine($"Error: {ex.ToString()}");
                        }

                    }
                }
            }
        }
    }
}
